from decimal import Decimal
from typing import List, Dict

from pydantic import BaseModel, Field, root_validator

from enums.spu_enum import SPUTypeEnum, SPUPriceTypeEnum, SPUSKUOnSaleEnum


def _validate_price(price_type, attrs: dict):
    original_price = attrs.get("original_price")
    cost_price = attrs.get("cost_price")
    sale_price = attrs.get("sale_price")
    original_point = attrs.get("original_point")
    cost_point = attrs.get("cost_point")
    if price_type == SPUPriceTypeEnum.money:
        if sale_price is None:
            raise ValueError("售价不能为空")
        if original_price:
            assert sale_price <= original_price, "原价高于售价"
        if cost_price:
            assert sale_price >= cost_price, "售价必须高于成本价"
        if original_point is not None or cost_point is not None:
            raise ValueError("现金支付的商品不允许设置积分")
    elif price_type == SPUPriceTypeEnum.point:
        if sale_price is not None:
            raise ValueError("积分商品不允许设置售价")
        if cost_point is None:
            raise ValueError("积分商品必须设置积分值")
    elif price_type == SPUPriceTypeEnum.money_and_point:
        if sale_price is None:
            raise ValueError("售价必须设置")
        if original_price:
            assert sale_price <= original_price, "原价高于售价"
        if cost_price:
            assert sale_price >= cost_price, "售价必须高于成本价"
        if cost_point is None:
            raise ValueError("积分值必须设置")
    return attrs


class NewSKUAttributeModel(BaseModel):
    attribute_key: int
    attribute_value: int


class AddNewSKUModel(BaseModel):
    outer_sku_id: str = Field(None, description="外部sku id")
    carousel_images: List[str] = Field(None, description="轮播图列表")
    thu_images: List[str] = Field(None, description="缩略图列表")
    detail_images: List[str] = Field(None, description="详情图列表")
    original_price: Decimal = Field(None, description="商品原价")
    cost_price: Decimal = Field(None, description="商品成本价")
    sale_price: Decimal = Field(None, description="商品售价")
    original_point: int = Field(None, description="商品原积分值")
    cost_point: int = Field(None, description="商品现在消耗的积分")
    extend_info: dict = Field(None, description="sku的扩展属性")
    attributes: List[NewSKUAttributeModel] = Field(..., description="sku的属性列表")


class AddNewSPUModel(BaseModel):
    spu_type: SPUTypeEnum = Field(..., description="spu商品类型")
    price_type: SPUPriceTypeEnum = Field(..., description="商品定价类型")
    outer_spu_id: str = Field(None, max_length=64, description="外部spu id")
    name: str = Field(..., description="商品名称", max_length=64)
    alias: str = Field(None, description="商品别名", max_length=128)
    # 暂定不允许在创建的时候就上架,需要等信息都完善再上架
    # onsale: SPUOnsaleEnum = Field(None, description="是否在售")
    # start_timestamp: int = Field(None, description="开售时间")
    # end_timestamp: int = Field(None, description="结束时间")
    carousel_images: List[str] = Field(None, description="轮播图列表")
    thu_images: List[str] = Field(None, description="缩略图列表")
    detail_images: List[str] = Field(None, description="详情图列表")
    video: str = Field(None, description="商品介绍视频", max_length=255)
    original_price: Decimal = Field(None, description="商品原价")
    cost_price: Decimal = Field(None, description="商品成本价")
    sale_price: Decimal = Field(None, description="商品售价")
    original_point: int = Field(None, description="商品原积分值")
    cost_point: int = Field(None, description="商品现在消耗的积分")
    extend_info: dict = Field(None, description="商品扩展属性")

    # 销售属性 组建sku的
    attribute_key_list: List[int] = Field(..., description="商品销售属性id列表, C端会根据这个列表展示销售属性")
    attribute_key_to_value_dict: Dict[int, List[int]] = Field(..., description="商品销售属性id对应的商品销售属性值列表,C端需要根据这个顺序展示")
    sku_list: List[AddNewSKUModel] = Field(..., description="sku 列表")

    currency: str = Field(None, description="币种,取租户的主币种")
    code: str = Field(None, description="商品编码,系统自动生成")

    @root_validator()
    def validate_root(cls, attrs: dict):
        price_type = attrs.get("price_type")
        # 校验spu价格信息
        _validate_price(price_type, attrs)
        # 校验sku价格信息
        sku_list = attrs.get("sku_list")
        for sku in sku_list:
            _validate_price(price_type, sku.dict())
        # 校验上下架的时间
        start_timestamp = attrs.get("start_timestamp")
        end_timestamp = attrs.get("end_timestamp")
        start_timestamp, end_timestamp = cls._validate_time(start_timestamp, end_timestamp)
        attrs["start_timestamp"] = start_timestamp
        attrs["end_timestamp"] = end_timestamp
        # 校验销售属性
        cls._validate_attribute(attrs.get("attribute_key_list"), attrs.get("attribute_key_to_value_dict"), sku_list)
        return attrs

    @staticmethod
    def _validate_time(start_timestamp, end_timestamp):
        if start_timestamp or end_timestamp:
            if len(str(start_timestamp)) == 13:
                start_timestamp = int(str(start_timestamp)[:10])
            if len(str(end_timestamp)) == 13:
                end_timestamp = int(str(end_timestamp)[:10])

        if all([start_timestamp, end_timestamp]):
            assert start_timestamp > 1000 and end_timestamp > 1000, "时间错误"
            assert end_timestamp > start_timestamp, "结束时间必须大于开始时间"
        return start_timestamp, end_timestamp

    @staticmethod
    def _validate_attribute(attribute_key_list: List[int],
                            attribute_key_to_value_dict: Dict[int, List[int]],
                            sku_list: List[AddNewSKUModel]):
        assert list(attribute_key_to_value_dict.keys()) == attribute_key_list, "销售属性不匹配"
        for sku in sku_list:
            sku_attribute_info = sku.attributes
            for each in sku_attribute_info:
                if each.attribute_key not in attribute_key_list or \
                        each.attribute_value not in attribute_key_to_value_dict[each.attribute_key]:
                    raise ValueError("销售属性不匹配")


class BulkSPUModel(BaseModel):
    spu_id_list: List[int] = Field(..., description="spu_id列表, 最多二十个", max_items=20)
    onsale: SPUSKUOnSaleEnum = Field(..., description="上下架状态")


class UpdateSPUReqModel(BaseModel):
    price_type: SPUPriceTypeEnum = Field(..., description="商品定价类型,不允许修改，传递进来就是用来做参数校验的")
    name: str = Field(None, max_length=64)
    alias: str = Field(None, max_length=128)
    carousel_images: List[str] = Field([], max_items=9)
    thu_images: List[str] = Field([], max_items=9)
    detail_images: List[str] = Field([], max_items=9)
    video: str = Field(None, max_length=255)
    original_price: Decimal = Field(None)
    cost_price: Decimal = Field(None)
    sale_price: Decimal = Field(None)
    original_point: int = Field(None)
    cost_point: int = Field(None)
    extend_info: dict = Field(None)

    @root_validator()
    def validate_root(cls, attr):
        price_type = attr.get("price_type")
        _validate_price(price_type, attr)
        return attr


if __name__ == '__main__':
    a = AddNewSPUModel(spu_type=SPUTypeEnum.real,
                   price_type=SPUPriceTypeEnum.money,
                   name="Aa",
                   attribute_key_list=["1", "2"],
                   attribute_key_to_value_dict={"1": ["11", "22"], "2": ["21", "22"]},
                   sale_price=10,
                   sku_list=[
                       {
                           "sale_price": 10,
                           "attributes": [
                               {
                                   "attribute_key": "1",
                                   "attribute_value": "11"
                               },
                               {
                                   "attribute_key": "2",
                                   "attribute_value": "22"
                               }
                           ]
                       },
                       {
                           "sale_price": 11,
                           "attributes": [
                               {
                                   "attribute_key": "1",
                                   "attribute_value": "22"
                               },
                               {
                                   "attribute_key": "2",
                                   "attribute_value": "21"
                               }
                           ]
                       }
                   ]
                   )
    print(a.dict(exclude_unset=True))